package main

import "time"

// 关于 functional options 简单来说就是通过类似闭包的方式来进行函数传参。
type options struct {
	timeout time.Duration
	caching bool
}

// Option overrides behavior of Connect
type Option interface {
	apply(*options)
}
type optionFunc func(*options)

func (f optionFunc) apply(o *options) {
	f(o)
}
func WithTimeout(t time.Duration) Option {
	return optionFunc(func(o *options) {
		o.timeout = t
	})
}
func WithCaching(cache bool) Option {
	return optionFunc(func(o *options) {
		o.caching = cache
	})
}

// Connect creates a connection.
type Connection struct {
}

const (
	defaultTimeout = 1 * time.Second
	defaultCaching = true
)

func Connect(addr string, opts ...Option) (*Connection, error) {
	options := options{
		timeout: defaultTimeout,
		caching: defaultCaching,
	}
	for _, o := range opts {
		o.apply(&options)
	}
	// ....
	return &Connection{}, nil
}

func main() {
	// Options must be provided only if needed.
	addr := ":8080"
	newTimeout := 3 * time.Second
	Connect(addr)
	Connect(addr, WithTimeout(newTimeout))
	Connect(addr, WithCaching(false))
	Connect(addr, WithTimeout(newTimeout), WithCaching(false))
}
